# @File    : ezqt.py

import sys
import typing

import PyQt5.Qt
import matplotlib.pyplot as plt
import numpy
import pandas
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.Qt import QTableWidget
from PyQt5.QtCore import QTimer, QObject
from PyQt5.QtGui import QValidator
from PyQt5.QtWidgets import QTableWidgetItem, QMainWindow, QApplication, QHeaderView
from matplotlib.backends.backend_qt import NavigationToolbar2QT
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg


def insert(tableWidget: QTableWidget):
    target = tableWidget.currentRow() + 1
    print("目标行号 = %d" % (target))
    tableWidget.insertRow(target)


def drop_selected_rows(tableWidget: QTableWidget):
    """
    删除表中选中的几行
    :param tableWidget:
    :return:
    """
    totalrows = tableWidget.rowCount()

    if totalrows < 1:
        print("无法继续删除，totalrows = ", totalrows)
        return

    ranges = (tableWidget.selectedRanges())

    for each_range in ranges:
        for r in range(each_range.topRow(), each_range.bottomRow() + 1):
            tableWidget.removeRow(r)

    return


def df_to_QTableWidget_with_header(df: pandas.DataFrame, tableWidget: QTableWidget):
    tableWidget.clear()
    tableWidget.setColumnCount(df.shape[1])
    tableWidget.setRowCount(df.shape[0])
    tableWidget.setHorizontalHeaderLabels(df.columns)
    tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

    for r in df.index:
        for c in range(df.columns.size):
            txt = str(df.iloc[r, c])
            if txt == "nan":
                txt = ""
            item = QTableWidgetItem(txt)

            tableWidget.setItem(r, c, item)


def QTableWidget_to_df(tableWidget: QTableWidget, to_float=False):
    """
    :return:
    """
    columnHeaders = []
    for j in range(tableWidget.columnCount()):
        columnHeaders.append(tableWidget.horizontalHeaderItem(j).text())
    df = pandas.DataFrame(columns=columnHeaders)
    for row in range(tableWidget.rowCount()):
        for col in range(tableWidget.columnCount()):
            item = tableWidget.item(row, col)
            if item and item.text():
                df.at[row, columnHeaders[col]] = item.text()
    return df.astype(float) if to_float else df


class QDoubleValidatorAllowNan(QtGui.QDoubleValidator):
    """
    空字符串可以直接通过的DoubleValidator
    """

    def __init__(self, *args, **kwargs):
        super(QDoubleValidatorAllowNan, self).__init__(*args, **kwargs)

    def validate(self, a0: str, a1: int) -> typing.Tuple[QValidator.State, str, int]:
        ref_res = super(QDoubleValidatorAllowNan, self).validate(a0, a1)
        state = ref_res[0]
        if state == QValidator.Intermediate and a0 == "":
            state = QValidator.Acceptable
        return state, a0, a1


class MainWindowKnowItselfShown(QMainWindow):
    """
    知道自己已经显示的主窗口。

    """
    sig_shown = QtCore.pyqtSignal()  # 表示自己显示了
    sig_hiden = QtCore.pyqtSignal()  # 表示自己隐藏了

    def __init__(self):
        super(MainWindowKnowItselfShown, self).__init__()

    def show(self) -> None:
        super(MainWindowKnowItselfShown, self).show()
        self.sig_shown.emit()

    def hide(self) -> None:
        super(MainWindowKnowItselfShown, self).hide()
        print("I am hidden, not killed")
        self.sig_hiden.emit()


class FollowerTimer(QObject):
    """
    从时钟，即一些较慢的时钟，主时钟timeout若干次，此时钟超时一次。
    可用于更新绘图区的计时器等对实时性要求较低的场合，
    以避免频繁更新可能造成的卡顿。
    """
    timeout_i = QtCore.pyqtSignal(int)

    def __init__(self, times: int, main_timer: QTimer):
        """

        :param times: 将画图时钟的周期设置为主时钟的多少倍
        """
        super(FollowerTimer, self).__init__()

        self.main_timer = main_timer
        self.times = times
        self.i = 0  # 记录主时钟超时了多少次
        self.main_timer.timeout.connect(self.__on_main_timer_timeout)

    def __on_main_timer_timeout(self):
        if self.i % self.times == 0:
            self.timeout_i.emit(
                self.i
            )
        self.i = (self.i + 1)


class EzCanvasWidget:
    """
    带有ToolBar的绘图部件
    """

    def __init__(self, parent: QtWidgets.QWidget, fig: plt.Figure = plt.Figure()):
        """
        :param parent: 空的widget
        """

        self.canvas_qtagg = FigureCanvasQTAgg(fig)
        layout2 = PyQt5.Qt.QVBoxLayout(parent)
        layout2.addWidget(self.canvas_qtagg)
        widget_for_toolbar = QtWidgets.QWidget(parent)
        fig_toolbar = NavigationToolbar2QT(self.canvas_qtagg, widget_for_toolbar)
        layout2.addWidget(fig_toolbar)

    def update_fig(self, fig):
        self.canvas_qtagg.figure = fig
        self.canvas_qtagg.draw()


if __name__ == '__main__':
    app = QApplication([])
    main_window = QMainWindow()
    widget = PyQt5.Qt.QWidget(main_window)
    main_window.setCentralWidget(widget)

    import matplotlib.pyplot as plt

    x = numpy.arange(0, 10, .1)
    y = numpy.sin(x)

    fig = plt.gcf()
    fig.gca().plot(x, y)

    canvas = EzCanvasWidget(widget, )
    canvas.update_fig(fig)
    fig2 = plt.Figure()
    fig2.gca().plot(x, x + y)
    canvas.update_fig(fig2)

    canvas.canvas_qtagg.figure.gca().plot(x, x * y)
    canvas.canvas_qtagg.draw()

    main_window.show()
    sys.exit(app.exec_())
